#pragma once
#include <iostream>
#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <unistd.h>
using namespace std;

const static int default_num = 5;

template <class T>
using func_t = function<void(T)>;

template <class T>
class threadpool
{
public:
    threadpool(func_t<T> f) // 构造的时候就直接开始创建线程,等待任务到来
        : _num(default_num), _vt(_num), _f(f)
    {
        for (int i = 0; i < _num; i++)
        {
            string name = "thread_" + to_string(i);
            //_vt[i] = thread(std::bind(&threadpool<T>::ThreadRun, this, placeholders::_1), name); // 线程不支持拷贝,移动赋值
            _vt[i] = thread(&threadpool<T>::ThreadRun, this, name); // 线程不支持拷贝,移动赋值

        }
    }
    void Push(const T &t)
    {
        sleep(1);
        _qt.push(t);
        // 唤醒线程去处理任务
        _cond.notify_one();
    }
    void ThreadRun(const string &name)
    {
        while (true)
        {
            unique_lock<mutex> mtx(_mtx);
            while (_qt.empty()) // 所以在唤醒的线程中还要继续判断是否为空
            {
                // 线程在等待的时候会释放锁，所有线程起初都会在wait处进行等待
                _cond.wait(mtx);
            }
            cout << name <<' ';
            _f(_qt.front()); // 处理任务
            _qt.pop();
            
            // 当线程处理完任务就会自动释放锁
        }
    }

    ~threadpool()
    {
        for(int i=0;i<_num;i++)
        {
            _vt[i].join();
        }
    }

private:
    int _num;           // 线程数量
    queue<T> _qt;       // 任务队列
    vector<thread> _vt; // 线程管理

    mutex _mtx;               // 锁
    condition_variable _cond; // 条件变量

    func_t<T> _f; // 回调, 线程所执行的任务
};
